package yunjiao.javatutorials.mq.component;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.stereotype.Component;
import yunjiao.javatutorials.mq.model.GenericMqMessage;
import yunjiao.javatutorials.mq.model.MqTopicEnum;

/**
 * MQ发送工具类（封装发送逻辑+重试+日志）
 *
 * @author yangyunjiao
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class MqMessageSender {
    private final RabbitTemplate rabbitTemplate;
    private final RetryTemplate retryTemplate;

    /**
     * 发送单条消息（泛型适配多业务类型）
     * @param topicEnum MQ主题枚举
     * @param businessType 业务类型（如USER/ORDER）
     * @param businessData 业务数据DTO
     * @param <T> 业务数据类型
     */
    public <T> void sendSingleMessage(MqTopicEnum topicEnum, String businessType, T businessData) {
        // 1. 构建统一消息体
        GenericMqMessage<T> mqMessage = GenericMqMessage.create(
                topicEnum.getExchange(),
                businessType,
                businessData
        );
        String messageId = mqMessage.getMessageId();

        try {
            // 2. 带重试机制发送消息
            retryTemplate.execute(context -> {
                // 关联消息ID（用于确认回调追踪）
                CorrelationData correlationData = new CorrelationData(messageId);
                // 发送消息（交换机+路由键+消息体+关联数据）
                rabbitTemplate.convertAndSend(
                        topicEnum.getExchange(),
                        topicEnum.getRoutingKey(),
                        mqMessage,
                        correlationData
                );
                log.info("消息发送成功：messageId={}, topic={}, businessType={}",
                        messageId, topicEnum.getExchange(), businessType);
                return null;
            });
        } catch (Exception e) {
            log.error("消息发送失败（已重试3次）：messageId={}, error={}",
                    messageId, e.getMessage(), e);
            // 可选：抛出异常/存入失败表，后续人工处理
            throw new RuntimeException("MQ消息发送失败：" + messageId, e);
        }
    }

    /**
     * 批量发送消息（优化性能：减少MQ连接次数）
     * @param topicEnum MQ主题枚举
     * @param businessType 业务类型
     * @param businessDataList 批量业务数据
     * @param <T> 业务数据类型
     */
    public <T> void sendBatchMessage(MqTopicEnum topicEnum, String businessType, Iterable<T> businessDataList) {
        for (T data : businessDataList) {
            sendSingleMessage(topicEnum, businessType, data);
        }
        log.info("批量消息发送完成：topic={}, businessType={}, 总条数={}",
                topicEnum.getExchange(), businessType, ((java.util.Collection<?>) businessDataList).size());
    }
}
